
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: ReferenceFieldModel.java 295 2010-01-13 21:03:17Z archie.cobbs $
 */

package org.dellroad.sidekar.schema.model;

import org.dellroad.sidekar.schema.SchemaMismatchException;

/**
 * Schema type representing reference types.
 */
public class ReferenceFieldModel extends SimpleFieldModel {

    public static final String NAME = "reference";

    private EntityModel referentModel;

    // Normal constructor
    public ReferenceFieldModel() {
        super(NAME);
    }

    // Copy constructor
    ReferenceFieldModel(ReferenceFieldModel original, SchemaModel schemaModel) {
        super(original);
        if (original.referentModel != null) {
            this.referentModel = schemaModel.getEntityModels().get(original.referentModel.getName());
            if (this.referentModel == null)
                throw new IllegalStateException();
        }
    }

    /**
     * Get the entity that is referenced by this field.
     */
    public EntityModel getReferentModel() {
        return this.referentModel;
    }
    public void setReferentModel(EntityModel referentModel) {
        this.referentModel = referentModel;
    }

    @Override
    public String getTypeDescription() {
        return this.referentModel.getName();
    }

    @Override
    public void validate(SchemaModel schema) {
        super.validate(schema);
        if (this.referentModel == null)
            throw new IllegalArgumentException("missing referent in " + this);
        if (schema.getEntityModels().get(this.referentModel.getName()) != this.referentModel) {
            throw new IllegalArgumentException("referent entity " + this.referentModel + " is not one of this schema's entities");
        }
    }

    @Override
    public <R> R visit(FieldModelSwitch<R> sw) {
        return sw.caseReferenceFieldModel(this);
    }

    @Override
    public void checkSameField(FieldModel model) {
        super.checkSameField(model);
        ReferenceFieldModel that = (ReferenceFieldModel)model;
        try {
            this.referentModel.checkSameEntity(that.referentModel);
        } catch (SchemaMismatchException e) {
            throw new SchemaMismatchException("referent entities differ: " + e.getMessage(), e);
        }
    }
}

